﻿#region

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

#endregion

namespace VinhSon.Intranet.Models.Security
{
    public class CustomAuthorizeContext
    {
        //private UnitOfWork _unitOfWork = new UnitOfWork();

        public bool IsAuthorized(AuthorizationContext filterContext)
        {
            string userName = (filterContext.HttpContext.User != null)
                                      ? filterContext.HttpContext.User.Identity.Name
                                      : "";

            // check if user don't log in
            if (string.IsNullOrEmpty(userName))
                return false;

            string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            string actionName = filterContext.ActionDescriptor.ActionName;
            //string verb = filterContext.RequestContext.HttpContext.Request.HttpMethod;

            Dictionary<string, BitArray> listUsers;
            Dictionary<int, string> dictionaryPermission;
            AppUtil.CheckInitialPermission(filterContext.HttpContext.Application, out listUsers, out dictionaryPermission);

            // First, check a action of control has been in list permission?
            string currentController = controllerName + ".";
            string currentAction = controllerName + "." + actionName;
            // group permission
            // get custom authorize from current action
            string currentGroup = "";
            CustomAuthorizeAttribute customAuthorizeAttribute = GetCustomAuthorizeFromAction(filterContext) ?? GetCustomAuthorizeFromController(filterContext);
            // check in controller if didn't granted on controller
            if (customAuthorizeAttribute != null)
                currentGroup = customAuthorizeAttribute.Key;

            List<KeyValuePair<int, string>> currentPermission = new List<KeyValuePair<int, string>>();
            currentPermission.AddRange(dictionaryPermission.Where(c => currentAction.Equals(c.Value, StringComparison.InvariantCultureIgnoreCase)));
            // check if don't have any action was defined in list, check if exists a controller is defined?
            if (currentPermission.Count == 0)
                currentPermission.AddRange(dictionaryPermission.Where(c => currentController.Equals(c.Value, StringComparison.InvariantCultureIgnoreCase)));
            // check if don't have any action or controller was defined in list, check if exists a group is defined?
            if (!string.IsNullOrEmpty(currentGroup))
                if (currentPermission.Count == 0)
                    currentPermission.AddRange(dictionaryPermission.Where(c => currentGroup.Equals(c.Value, StringComparison.InvariantCultureIgnoreCase)));

            // allow if action of controller isn't defined in list
            if (currentPermission.Count == 0)
                return customAuthorizeAttribute == null;

            BitArray bitArray = listUsers.ContainsKey(userName)
                                        ? listUsers[userName]
                                        : AppUtil.InitializeUser(listUsers, dictionaryPermission, userName);

            bool isAuthorize = false;
            if (bitArray != null)
                if (currentPermission.Where(item => item.Key <= bitArray.Length).Any(item => bitArray[item.Key - 1]))
                {
                    isAuthorize = true;
                }

            return isAuthorize;
        }

        private CustomAuthorizeAttribute GetCustomAuthorizeFromAction(AuthorizationContext filterContext)
        {
            CustomAuthorizeAttribute attr = filterContext.ActionDescriptor.GetCustomAttributes(typeof(CustomAuthorizeAttribute), true).FirstOrDefault() as CustomAuthorizeAttribute;
            return attr;
        }

        private CustomAuthorizeAttribute GetCustomAuthorizeFromController(AuthorizationContext filterContext)
        {
            ControllerBase controller = filterContext.Controller;
            if (controller != null)
            {
                Type type = controller.GetType();
                CustomAuthorizeAttribute attr = type.GetCustomAttributes(typeof(CustomAuthorizeAttribute), true).FirstOrDefault() as CustomAuthorizeAttribute;
                return attr;
            }
            return null;
        }
    }
}
